package flash.sound.file.wave {
 
  import flash.sound.audio.format.BitsPerSample;
  import flash.sound.audio.format.IAudioFormat;
  import flash.sound.file.AudioFile;
  import flash.sound.file.wave.tag.IWaveTag;
  import flash.sound.file.wave.tag.WaveDataTag;
  import flash.sound.file.wave.tag.WaveFormatTag;
  import flash.sound.file.wave.tag.header.IWaveTagHeader;
  import flash.sound.file.wave.tag.header.WaveTagHeader;
  import flash.utils.ByteArray;
  import flash.utils.IDataInput;
  
  public class WaveFile extends AudioFile {
          
    public var fileType: String;
    
    public var fileSize: int;
    
    public var fileFormat: String;
    
    public var tags: Array = [];
    
    public function WaveFile(bytes: ByteArray) {
      super(bytes);
    }
    
    public function readWaveTag(stream: IDataInput): IWaveTag {
      var header: IWaveTagHeader = new WaveTagHeader();
      header.read(stream);
      var tag: IWaveTag = WaveTagFactory.createWaveTag(header);
      tag.read(stream);
      return tag; 
    }
        
    override public function read(): Boolean {              
      data.position = 0;      
      if (data.length < 44) {
        return false;
      }              
      fileType = data.readMultiByte(4, 'ascii');
      
      fileSize = data.readUnsignedInt();
      
      fileFormat = data.readMultiByte(4, 'ascii');
      
      while (data.bytesAvailable) {
        var tag: IWaveTag = readWaveTag(data);
        tags.push(tag);
      }                                          
      return true; 
    }
    
    override public function write(): Boolean {
      return false;
    }    

    protected function get dataTag(): WaveDataTag {
      var tag: IWaveTag = getTagById(WaveTagFactory.DATA_TAG_ID);
      return WaveDataTag(tag);
    }
  
    protected function get formatTag(): WaveFormatTag {
      var tag: IWaveTag = getTagById(WaveTagFactory.FORMAT_TAG_ID);
      return WaveFormatTag(tag);        
    }
  
    protected function getTagById(id: String): IWaveTag {
      for each (var tag: IWaveTag in tags) {
        if (!tag.header) {
          continue;
        }
        if (tag.header.id == id) {
          return tag;
        }
      }
      return null;
    }    

    /**
    * 
    */
    override public function readAudio(position: int, samples: int, format: IAudioFormat): ByteArray {
      var buffer: ByteArray = new ByteArray();
      //buffer.endian = Endian.LITTLE_ENDIAN;
      var waveFormat: WaveFormatTag = formatTag;
      var waveData: WaveDataTag = dataTag;
      var currentPosition: int = 0;
      if (position != 0) {
        currentPosition = position % waveData.data.length;
      }         
      //waveData.data.position = currentPosition;
      while (samples > 0) {        
        var left: Number = 0;
        var right: Number = 0;        
        if (waveFormat.bitsPerSample == BitsPerSample.BITS_8) {
          if (waveData.data.position > waveData.data.length) {
            waveData.data.position = 0;
          }        
          if (waveFormat.channels == 1) {
            left = waveData.data.readByte();
            right = left;
          } else if (waveFormat.channels == 2) {
            left = waveData.data.readByte();
            right = waveData.data.readByte();
          } else {
            throw "channels > 2";
          } 
        } else if (waveFormat.bitsPerSample == BitsPerSample.BITS_16) {
          if (waveData.data.position > waveData.data.length - 2) {
            waveData.data.position = 0;
          }        
          if (waveFormat.channels == 1) {
            left = waveData.data.readShort();
            right = left;
          } else if (waveFormat.channels == 2) {
            left = waveData.data.readShort();
            right = waveData.data.readShort();
          } else {
            throw "channels > 2";
          } 
        } else {
          throw "only 8 bit || 16 bit";
        }           
        if (waveFormat.bitsPerSample == BitsPerSample.BITS_8) {            
          left = (left - 127) / 127;
          right = left;
        } else {
          left = left / 32767;
          right = right / 32767;
        }          
        buffer.writeFloat(left);
        buffer.writeFloat(right);
        samples--;
      }                       
      buffer.position = 0;
      return buffer;
    }
  }  
}